package com.alibaba.dubbo.dynamic.service.impl;

import com.alibaba.dubbo.dynamic.config.DynamicExportConfig;
import com.alibaba.dubbo.dynamic.dao.JarDao;
import com.alibaba.dubbo.dynamic.model.Dynamic;
import com.alibaba.dubbo.dynamic.model.Jar;
import com.alibaba.dubbo.dynamic.model.query.JarExample;
import com.alibaba.dubbo.dynamic.service.JarService;
import com.alibaba.dubbo.dynamic.utils.ClassUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created on 2016/8/14 07:29.
 */
@RestController
public class JarServiceImpl extends BaseRestImpl<Jar, JarExample, Integer> implements JarService {

    @Autowired
    private JarDao jarDao;


    @Value("${dynamic.upload-path}")
    private String uploadPath;


    @RequestMapping(value = "/listJars")
    public List<String> listJars() {

        String[] list = getUploadFile().list(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.lastIndexOf(".jar") != -1;
            }
        });
        if (list == null) {
            return new ArrayList<String>();
        }
        return Arrays.asList(list);
    }


    @RequestMapping(value = "/upload")
    public void upload(MultipartFile file) throws IOException {
        File outfile = new File(getUploadFile().getAbsolutePath() + "/" + file.getOriginalFilename());
        if (!outfile.exists()) {
            file.transferTo(outfile);
        }
    }


    @RequestMapping(value = "/lib", method = RequestMethod.GET)
    public ResponseEntity<StreamingResponseBody> downJar(@RequestParam(value = "jar") final String jar) throws IOException {
        final File jarFile = new File(uploadPath + "/" + jar);
        StreamingResponseBody streamingResponseBody = new StreamingResponseBody() {
            public void writeTo(OutputStream outputStream) throws IOException {

                FileInputStream in = new FileInputStream(jarFile);
                IOUtils.copy(in, outputStream);
            }
        };

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        httpHeaders.setContentDispositionFormData("attachment", jar);
        return new ResponseEntity<StreamingResponseBody>(streamingResponseBody, httpHeaders, HttpStatus.OK);
    }

    @RequestMapping(value = "/scanJar", method = RequestMethod.GET)
    public List<Dynamic> scanJar(@RequestParam(value = "jar") String jar) throws IOException, ClassNotFoundException {
        final File jarFile = new File(uploadPath);
        List<Class> filter = Arrays.<Class>asList(Component.class,
                Service.class,
                Controller.class,
                com.alibaba.dubbo.config.annotation.Service.class,
                ControllerAdvice.class,
                RestController.class,
                RestControllerAdvice.class,
                Repository.class
        );
        File[] files = jarFile.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.lastIndexOf(".jar") != -1;
            }
        });
        if (files == null) {
            return new ArrayList<Dynamic>();
        }

        URL[] urls = new URL[files.length];
        for (int i = 0; i < files.length; i++) {
            urls[i] = new URL("file:/" + files[i].getAbsolutePath());
        }

        List<Class> classWithAnno = ClassUtils.findClassWithAnno(new URL("file:/" + getUploadFile().getAbsolutePath() + "/" + jar), urls, filter);
        List<Dynamic> configs = new ArrayList<Dynamic>();
        for (Class clazz : classWithAnno) {
            Dynamic dynamicExportConfig = new Dynamic();
            Class[] interfaces = clazz.getInterfaces();
            if (interfaces.length > 0) {
                dynamicExportConfig.setInterfaceName(interfaces[0].getName());
            }
            dynamicExportConfig.setServiceName(clazz.getName());
            String firstLowC = clazz.getSimpleName().substring(0, 1).toLowerCase();
            dynamicExportConfig.setBeanId(firstLowC + clazz.getSimpleName().substring(1));
            configs.add(dynamicExportConfig);
        }
        return configs;
    }

    public File getUploadFile() {
        File file = new File(uploadPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

    public void setDao() {
        this.baseDao = jarDao;
    }

}